﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WinScriptEngine.Parses.Interface;
using System.Globalization;
using WinScriptEngine.Parses.Scope;
using WinScriptEngine.Parses.Basic;

namespace WinScriptEngine.Parses.Impl
{
    delegate bool OperatorCallback(InvokeEnvironment cpu);
    class Operator
    {

        public static readonly Operator SplitOperator = null;
        /// <summary>
        /// 操作符字符串
        /// </summary>
        public string name;
        /// <summary>
        /// 几目
        /// </summary>
        public int countOfParam;
        /// <summary>
        /// 优先级
        /// </summary>
        public int upperLevel;
        /// <summary>
        /// 结合性（优先级等于情况下优先还是让步）
        /// </summary>
        public bool isCombineRight;
        /// <summary>
        /// 操作函数
        /// </summary>
        public OperatorCallback operatorCallback;

        public Operator(string name, int countOfParam, int upperLevel, bool isCombineRight, OperatorCallback operatorCallback)
        {
            this.name = name;
            this.countOfParam = countOfParam;
            this.upperLevel = upperLevel;
            this.isCombineRight = isCombineRight;
            this.operatorCallback = operatorCallback;
        }

        /// <summary>
        /// 计算优先级（当前优先级加右结合性与参数level对比）
        /// </summary>
        /// <param name="level">对比的优先级</param>
        /// <returns>&gt; 0 (自身优先级高)，== 0(相等),&lt; 0 （自身优先级底）</returns>
        public int CompareLevel(int level)
            => level - (this.upperLevel - Convert.ToInt32(this.isCombineRight));
    }

    [Serializable]
    public class OperatorRuntimeException : RuntimeException
    {
        public OperatorRuntimeException() { }
        public OperatorRuntimeException(string message) : base(message) { }
        public OperatorRuntimeException(string message, Exception inner) : base(message, inner) { }
        protected OperatorRuntimeException(
          System.Runtime.Serialization.SerializationInfo info,
          System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
    }
    /// <summary>
    /// 操作符解析类
    /// </summary>
    class OperatorParseImpl : SingletonObject<OperatorParseImpl>, IParse
    {
        #region ==== 操作符列表 ====
        // 为了兼容相同的运算符在不同场景的不同作用
        Dictionary<string, Operator[]> operatorMap = new()
        {
            { "|=", new[] { new Operator("|=", 2, 14, true, OperatorMethod.NotImplemented) } },
            { "^=", new[] { new Operator("^=", 2, 14, true, OperatorMethod.NotImplemented) } },
            { "&=", new[] { new Operator("&=", 2, 14, true, OperatorMethod.NotImplemented) } },
            { ">>=", new[] { new Operator(">>=", 2, 14, true, OperatorMethod.NotImplemented) } },
            { "-=", new[] { new Operator("-=", 2, 14, true, OperatorMethod.NotImplemented) } },
            { "+=", new[] { new Operator("+=", 2, 14, true, OperatorMethod.NotImplemented) } },
            { "%=", new[] { new Operator("%=", 2, 14, true, OperatorMethod.NotImplemented) } },
            { "*=", new[] { new Operator("*=", 2, 14, true, OperatorMethod.NotImplemented) } },
            { "/=", new[] { new Operator("/=", 2, 14, true, OperatorMethod.NotImplemented) } },
            { "=", new[] { new Operator("=", 2, 14, true, OperatorMethod.Assign) } },

            { "?", new[] { new Operator("?", 3, 13, true, OperatorMethod.NotImplemented) } },

            { "||", new[] { new Operator("||", 2, 12, false, OperatorMethod.NotImplemented) } },
            { "&&", new[] { new Operator("&&", 2, 11, false, OperatorMethod.NotImplemented) } },
            { "|", new[] { new Operator("|", 2, 10, false, OperatorMethod.NotImplemented) } },
            { "^", new[] { new Operator("^", 2, 9, false, OperatorMethod.Xor) } },
            { "&", new[] { new Operator("&", 2, 8, false, OperatorMethod.NotImplemented) } },
            { "!=", new[] { new Operator("!=", 2, 7, false, OperatorMethod.NotImplemented) } },
            { "==", new[] { new Operator("==", 2, 7, false, OperatorMethod.NotImplemented) } },

            { ">", new[] { new Operator(">", 2, 6, false, OperatorMethod.NotImplemented) } },
            { ">=", new[] { new Operator(">=", 2, 6, false, OperatorMethod.NotImplemented) } },
            { "<", new[] { new Operator("<", 2, 6, false, OperatorMethod.NotImplemented) } },
            { "<=", new[] { new Operator("<=", 2, 6, false, OperatorMethod.NotImplemented) } },

            { "<<", new[] { new Operator("<<", 2, 5, false, OperatorMethod.NotImplemented) } },
            { ">>", new[] { new Operator(">>", 2, 5, false, OperatorMethod.NotImplemented) } },

            { "+", new[] { new Operator("+", 2, 4, false, OperatorMethod.Add), new Operator("+", 1, 2, true, OperatorMethod.Plus) } },
            { "-", new[] { new Operator("-", 2, 4, false, OperatorMethod.Sub), new Operator("-", 1, 2, true, OperatorMethod.Neg) } },

            { "/", new[] { new Operator("/", 2, 3, false, OperatorMethod.Div) } }, 
            { "*", new[] { new Operator("*", 2, 3, false, OperatorMethod.Mul) } },
            { "%", new[] { new Operator("%", 2, 3, false, OperatorMethod.Surplus) } },

            { "++", new[] { new Operator("++", 1, 2, true, OperatorMethod.NotImplemented), new Operator("++", 1, 2, false, OperatorMethod.NotImplemented) } },
            { "--", new[] { new Operator("--", 1, 2, true, OperatorMethod.NotImplemented), new Operator("--", 1, 2, false, OperatorMethod.NotImplemented) } },
            //{ "*", new[] { new Operator("*", 1, 2, true, NotImplemented) } },
            //{ "&", new[] { new Operator("&", 1, 2, true, NotImplemented) } },
            { "!", new[] { new Operator("!", 1, 2, true, OperatorMethod.NotImplemented) } },
            { "~", new[] { new Operator("~", 1, 2, true, OperatorMethod.Reverse) } },
            //{ "sizeof", new[] { new Operator("sizeof", 1, 2, true, NotImplemented) } },

            //{ "[", new[] { new Operator("[", 1, 2, false, NotImplemented) } },
            //{ "(", new[] { new Operator("(", 1, 2, false, NotImplemented) } },
            //{ ".", new[] { new Operator(".", 2, 2, false, NotImplemented) } },
            //{ "->", new[] { new Operator("->", 2, 2, false, NotImplemented) } }
        };
        #endregion
        public string VTypeName => "Operator";
        public bool Invoke(InvokeEnvironment vCpu)
        {
            Metadata value = vCpu.instructions[vCpu.eip];
            Operator[] operators;
            if (!operatorMap.TryGetValue(value.@object, out operators))
                throw new OperatorRuntimeException("Invalid operator");

            Operator canUseOperator = null;
            foreach (Operator @operator in operators)
            {
                switch (@operator.countOfParam)
                {
                    case 1:
                        if (vCpu.needNumber == Convert.ToInt32(@operator.isCombineRight))
                        {
                            canUseOperator = @operator;
                        }
                        break;
                    case 2:
                    case 3:
                        if (vCpu.needNumber == 0)
                        {
                            canUseOperator = @operator;
                            vCpu.needNumber += @operator.countOfParam - 1;
                        }
                        break;
                    default:
                        throw new OperatorRuntimeException("Invalid operator operand");
                }
                if (canUseOperator != null)
                    break;
            }
            if (canUseOperator == null)
                throw new OperatorRuntimeException("Invalid operator");

            if (canUseOperator.CompareLevel(vCpu.operLevel) <= 0)
            {
                vCpu.operLevel = canUseOperator.upperLevel;
                vCpu.ClearOperatorCache();
            }
            vCpu.operLevel = canUseOperator.upperLevel;
            vCpu.operators.Push(canUseOperator);
            return true;
        }
        public Metadata Parse(ref Metadata upper, IEnumerator<char> position)
        {
            string operatorString = "";
            StringBuilder operatorBuilder = new();
            do
            {
                if (!CheckCallback(position.Current))
                    break;

                operatorBuilder.Append(position.Current);
                operatorString = operatorBuilder.ToString();
                if (operatorMap.TryGetValue(operatorString, out _))
                    continue; 

                // 贪婪模式，直到找不到标识符为止
                if (operatorString.Length <= 1)
                    throw new OperatorRuntimeException("Invalid operator");

                operatorString = operatorBuilder.ToString(0, operatorString.Length - 1);
                break;
            }
            while (position.MoveNext());
            return new Metadata(MetadataType.Oper,operatorString);
        }

        public bool TryParse(ref Metadata upper, char curChar)
        {
            return CheckCallback(curChar);
        }
        /// <summary>
        /// 检查是否是符号字符
        /// </summary>
        /// <param name="curChar">被检查的字符</param>
        /// <returns>是否时符号字符</returns>
        public bool CheckCallback(char curChar)
        {
            return curChar >= 0x21 && curChar <= 0x2f
                || curChar >= 0x3A && curChar <= 0x3F
                || curChar >= 0x5B && curChar <= 0x60
                || curChar >= 0x7B && curChar <= 0x7E;
        }
    }
}
